feat: add signet-rpc-storage crate with ETH RPC endpoints#75
feat: add signet-rpc-storage crate with ETH RPC endpoints#75
Conversation
|
[Claude Code] Review SummaryWhat's here
Issues flagged (inline comments)
Codebase health
|
Add the foundational scaffolding for the signet-rpc-storage crate, which provides an Ethereum JSON-RPC server backed by signet-storage's unified storage backend, independent of reth's FullNodeComponents. This includes: - Workspace dependency additions (signet-storage, signet-cold, signet-hot, signet-storage-types) - StorageRpcCtx context struct with Arc<Inner> pattern - BlockTags atomic block tag tracker for Latest/Safe/Finalized - Block ID and block tag resolution utilities - Stub eth module (endpoints to be added in follow-up) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement all ETH namespace JSON-RPC endpoints backed by cold/hot storage instead of reth. Converts eth.rs placeholder into eth/ directory module with error types, helpers, and 24 supported endpoint handlers: - Simple queries: blockNumber, chainId - Block queries: getBlockByHash/Number, getBlockReceipts, headers - Transaction queries: getTransactionByHash, getTransactionReceipt, raw txs - Account state (hot storage): getBalance, getStorageAt, getCode, getTransactionCount - EVM execution: call, estimateGas (via signet-evm/trevm) - Transaction submission: sendRawTransaction (via TxCache) - Logs: getLogs with bloom filter matching Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 23 integration tests covering all endpoint categories: simple queries, block/transaction lookups, account state, logs, and error cases. Tests exercise the router through the axum service layer using tower's oneshot(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- send_raw_transaction: log warning on forwarding failure instead of silently discarding the error - get_logs: reject reversed block ranges (from > to) with an explicit error instead of silently returning empty results - build_receipt_envelope: remove catch-all arm so new TxType variants from alloy produce a compile error instead of a runtime panic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regular txs execute before system txs, not the other way around. Drive-by from #74 (comment) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4341320 to
601c156
Compare
- Extract `resolve_evm_block` method on `StorageRpcCtx` to deduplicate the block resolution + header fetch + revm db creation shared by `call()` and `estimate_gas()`. Resolves headers directly (by hash or by tag→number) to avoid redundant cold storage lookups. - Replace glob import `use endpoints::*` with explicit imports. - Remove unused `revm_state()` method from `StorageRpcCtx`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ounds - Move `resolve_block_id` and `resolve_block_number_or_tag` from free functions in resolve.rs to `resolve_block_id` and `resolve_block_tag` methods on `StorageRpcCtx`. This eliminates repeated `ctx.tags()` and `ctx.cold()` threading at every call site. - `resolve_block_tag` returns `u64` directly (infallible) instead of `Result`, simplifying callers like `get_logs`. - Remove `H::RoTx: Send + Sync + 'static` bounds from all endpoint functions, router, and ctx methods — the trait already provides these. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the bare `rpc_gas_cap` constructor parameter with a `StorageRpcConfig` struct that bundles all RPC configuration. This moves `max_blocks_per_filter` from a hard-coded constant to a configurable value, adds `max_logs_per_response` enforcement in `eth_getLogs`, and pre-creates a tracing semaphore for future debug endpoint concurrency limiting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add gas oracle, filters, subscriptions, debug tracing, and signet namespaces to signet-rpc-storage. Port 15 endpoints from the old reth-backed signet-rpc crate to the storage-backed architecture. New modules: - gas_oracle: cold-storage gas price oracle (suggest_tip_cap) - interest/: filter manager, subscription manager, block notifications - debug/: traceBlockByNumber, traceBlockByHash, traceTransaction - signet/: sendOrder, callBundle Wired eth endpoints: gasPrice, maxPriorityFeePerGas, feeHistory, newFilter, newBlockFilter, uninstallFilter, getFilterChanges, getFilterLogs, subscribe, unsubscribe. Integration tests cover gas/fee queries, filter lifecycle, and debug tracing with noop tracer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use `SealedHeader` with `.hash()` / `.into_inner()` instead of `header.hash_slow()` - Use `RecoveredTx` (pre-recovered sender) instead of manual `recover_sender` calls - Use `ColdReceipt` with per-tx `gas_used` instead of computing deltas from cumulative gas - Delegate `get_logs` to cold storage instead of manual bloom filtering and block iteration - Remove `BlockRangeInclusiveIter`, `collect_matching_logs`, `build_receipt_from_parts`, and `recover_sender` helpers - Simplify `build_rpc_transaction` and `build_receipt` to be infallible Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses PR review feedback: - resolve_block_id now uses hot HotDbRead::get_header_number instead of cold storage, making it synchronous and avoiding async overhead - Add resolve_header for direct header fetches from hot storage, eliminating the double header lookup in header_by - Change not_supported() to return method_not_found() (JSON-RPC -32601) instead of internal_error (-32603) - Update ResolveError to use Storage/Db variants instead of Cold - Update tests to write headers to both hot and cold storage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap return types to use RpcBlock/RpcReceipt/RpcTransaction/RpcHeader type aliases, rename tx_by_block_and_index to match rpc naming, fix not_supported error message, and split call into run_call + call. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align rpc-storage behavioral semantics with the rpc crate: - subscribe: require filter for Logs, reject filter for NewHeads via TryFrom impl - send_raw_transaction: return Result from spawned task instead of swallowing errors - uninstall_filter/unsubscribe: add HandlerCtx and wrap in spawn_blocking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…to 0.5 resolve_evm_block previously mapped Pending to Latest without modifying the header, causing eth_estimateGas (which defaults to Pending) and eth_call with explicit Pending to see wrong block.number, timestamp, and base_fee. Now synthesizes a next-block header matching signet-rpc's block_cfg() behavior. Also refactors callBundle to use resolve_evm_block instead of duplicating the pending header logic inline, and passes max_logs to cold.get_logs() for early termination (signet-cold 0.5 API). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich
left a comment
There was a problem hiding this comment.
are there ways that we can DRY endpoint logic or definitions?
* refactor: rewrite block processor to use signet-hot storage Replace the reth ProviderFactory-based storage with HotKv for rollup state reads. The processor becomes a stateless executor that reads from hot storage, runs the EVM, and returns ExecutedBlock. Extraction is moved to the node (PR3) to avoid lifetime issues with borrowed Extracts. - Replace Db: NodeTypesDbTrait generic with H: HotKv - Replace state_provider_database() with revm_state() using RevmRead - Remove on_host_commit() and commit_evm_results() - Add process_block() returning ExecutedBlock - Add build_executed_block() for type conversion - Remove signet-db, signet-node-types, reth-exex, reth-node-api deps - Add signet-hot, signet-storage-types deps - Remove Chain/PrimitivesOf/ExExNotification type aliases from lib.rs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: rewrite signet-node to use unified storage and rpc-storage Replace reth's ProviderFactory/BlockchainProvider with UnifiedStorage and swap signet-rpc for signet-rpc-storage. The node now holds Arc<UnifiedStorage<H>> and shares state with the RPC context through BlockTags (atomic block tag tracking) and broadcast::Sender (new block notifications). Key changes: - StorageRpcCtx accepts Arc<UnifiedStorage<H>> for shared ownership - Node struct uses HotKv generic instead of NodeTypesDbTrait - Block processing uses signet-extract's Extractor + ExtractableChainShim - Genesis loading via HistoryWrite::load_genesis + UnsafeDbWrite::commit - Fix metrics bug: record_notification_received now correctly increments the received counter instead of the processed counter Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: rewrite node-tests to use unified storage and align gas oracle Replace TmpDb/ProviderFactory with MemKv/UnifiedStorage in all node test infrastructure. Update signet-storage crates to v0.6.2 to fix MemKv intra-transaction read visibility. Align the cold-storage gas oracle with reth's GasPriceOracle by adding default_gas_price (1 Gwei), ignore_price (2 wei), and max_price (500 Gwei) to StorageRpcConfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: delete signet-db, signet-node-types, and signet-rpc These crates are fully replaced by signet-storage, signet-hot, and signet-rpc-storage respectively. Remove 6,700+ lines of dead code and clean up 22 unused workspace dependencies. Replace reth-db tempdir_path with tempfile in signet-node-config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: rename signet-rpc-storage to signet-rpc Reclaim the signet-rpc name now that the old reth-backed crate is deleted. Rename directory, package, and all import paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: restore RUN EVM ascii art banner Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve clippy empty_line_after_doc_comments warning in ascii banner Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review — bugs, style, and test infra - Fix log_index per-receipt → per-block (kind.rs) - Fix hash/height mismatch in update_highest_processed_height (node.rs) - Fix serve_ipc panic: expect → ? (serve.rs) - Use seal_unchecked to avoid redundant header re-hashing (processor.rs) - Refactor imperative event loop → functional chain (processor.rs) - Add #[instrument(skip_all)] to run_evm and build_executed_block - Add TODO for two-reader consistency risk (processor.rs) - Group signet_hot imports across 6 RPC files - Move supported methods above "Unsupported" comment (eth/mod.rs) - Hoist function-scoped imports to module level (eth_rpc.rs) - Fix stale signet_rpc_storage reference (eth_rpc.rs) - Differentiate HTTP/WS doc comments, fix Result type (serve.rs) - Wrap cold storage polling loop in 30s timeout (context.rs) - Remove dead signet_events_in_range method (context.rs) - Update README to reflect new API types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Remove `not_supported` pattern; unregistered methods return `method_not_found` by default in ajj (threads 14, 15) - Simplify `SubscriptionNotification`: hardcode `jsonrpc`/`method` in manual `Serialize` impl instead of storing as fields (threads 18, 19) - Change `send_order` return type to `ResponsePayload<(), SignetError>` and add fire-and-forget doc comment (threads 5, 7) - Use `ctx.resolve_header()` (hot storage) instead of `cold.get_header_by_number()` in debug endpoints (threads 12, 13) - Replace `DebugError::Cold(String)` / `Hot(String)` with concrete `#[from]` error types; remove `Clone` derive and `into_string` (thread 10) - Parallelize gas oracle transaction reads with `JoinSet` (thread 21) - Add `tokio-stream` and `tokio-util` to workspace deps (thread 22) - Add blob gas vec compatibility comment (thread 23) - Add `State<Db>` / `DatabaseCommit` documentation (thread 20) - Update README with namespace overview and unsupported methods (thread 16) - Add blank lines in lib.rs between module groups (thread 2) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… Paris `EthereumHardfork` is a bitflags type where each hardfork is an independent bit. All callers of `load_genesis()` were passing only `EthereumHardfork::Paris`, so `genesis_header()` never set `base_fee_per_gas` (a London feature) because the London bit was unset. The test context worked around this by patching the header after the fact. This adds `genesis_hardforks()` to signet-genesis, which derives the correct set of active hardfork flags by inspecting the chain config's activation blocks and timestamps. Per-network LazyLock statics and a `GenesisSpec::genesis_hardforks()` method are also provided. The workaround in the test context is removed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… PairedHeights - Unify BlockTags + notification sender into ChainNotifier shared struct - Replace log-only cold_lag check with proper storage reconciliation (unwind to min of hot/cold tips on startup) - Fix PairedHeights 0/0 fallback to use genesis heights with let-else - Remove TODO about reader snapshots and redundant map_err - Replace fully-qualified HotDbRead/HistoryRead syntax with method calls Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The builder previously only loaded genesis into hot storage. Cold-backed RPC queries for block 0 would fail. Now prebuild checks cold independently and writes the genesis block if absent. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich
left a comment
There was a problem hiding this comment.
how is the storage backend configured in node config?
… merge gas cache - Bump signet-sdk crates from 0.16.0-rc.8 to 0.16.0-rc.11 - Migrate to new block primitives (Sealed<Header>, SealedBlock<T>) - Replace ChainSpec with EthereumHardfork bitflags in block processor - Restructure processor to be instantiated per-block instead of held - Merge build_executed_block into run_evm, change map_err to wrap_err - Fix changed flag: on_host_revert/process_committed_chain return bool - DRY reader/last_block/drop pattern into last_rollup_block() helper - Remove blank line between imports in gas_oracle.rs - Merge PR #80: add lock-free GasOracleCache for tip suggestions Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
| block: AtomicU64, | ||
| /// Cached tip value. | ||
| tip: AtomicU64, |
There was a problem hiding this comment.
Having these fields as two separate atomics means there's a slight window for a race. I'm not sure if it's worth worrying about though, given how small the window is, and (I think) the repercussions are likely insignificant.
There was a problem hiding this comment.
i think the race is fine here. not too concerned about it. same with the race in updating the block tags
There was a problem hiding this comment.
[Claude Code]
Agreed the race is benign — worst case a reader gets a stale tip value for one request, which is already acceptable since gas prices are advisory. An AtomicU128 packing both fields would close the window, but adds complexity for no practical benefit. Leaving as-is seems right.
…C config Fix EVM spec_id for RPC calls: all EVM execution paths (eth_call, eth_estimateGas, eth_createAccessList, debug tracing, bundle simulation) now derive the correct SpecId from chain config + block header instead of defaulting to PRAGUE. Move serve.rs from signet-node to signet-rpc: transport infrastructure (HTTP/WS/IPC) is now reth-free, using tokio::spawn and Handle::current() instead of reth's TaskExecutor. This removes axum, tower-http, interprocess, and ajj dependencies from signet-node. Load StorageRpcConfig from host RpcServerArgs: rpc_gas_cap, max_tracing_requests, and gas price oracle settings now flow through from reth's CLI args instead of always using defaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix misleading doc on resolve_evm_block: state is loaded at latest, not finalized - Fix off-by-one in getLogs block range check: inclusive range of from..=to spans to-from+1 blocks, so check >= not > - Remove incorrect override of pending block gas_limit with rpc_gas_cap; the parent header's gas_limit (inherited via into_inner) is correct Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix off-by-one in calculate_reward_percentiles that could skip the last transaction or panic on index out of bounds - Remove unused parent_header SealedHeader conversion in block processor - Use spawn_with_ctx (async) instead of spawn_blocking_with_ctx for send_order which only does async work - Add clarifying comment on per-block hardfork construction in node Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… code Bump signet-storage ecosystem deps (storage, cold, hot, types) from 0.6.2 to 0.6.4 and add signet-hot-mdbx / signet-cold-mdbx workspace deps. Introduce StorageConfig in signet-node-config with FromEnv derive and a build_storage() method that opens hot+cold MDBX backends and returns UnifiedStorage<DatabaseEnv>. Replace the old database_path field and remove dead RocksDB helpers (database_path_str, rocksdb_path, open_rocks_db). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove `not_supported` pattern; unregistered methods return `method_not_found` by default in ajj (threads 14, 15) - Simplify `SubscriptionNotification`: hardcode `jsonrpc`/`method` in manual `Serialize` impl instead of storing as fields (threads 18, 19) - Change `send_order` return type to `ResponsePayload<(), SignetError>` and add fire-and-forget doc comment (threads 5, 7) - Use `ctx.resolve_header()` (hot storage) instead of `cold.get_header_by_number()` in debug endpoints (threads 12, 13) - Replace `DebugError::Cold(String)` / `Hot(String)` with concrete `#[from]` error types; remove `Clone` derive and `into_string` (thread 10) - Parallelize gas oracle transaction reads with `JoinSet` (thread 21) - Add `tokio-stream` and `tokio-util` to workspace deps (thread 22) - Add blob gas vec compatibility comment (thread 23) - Add `State<Db>` / `DatabaseCommit` documentation (thread 20) - Update README with namespace overview and unsupported methods (thread 16) - Add blank lines in lib.rs between module groups (thread 2) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… PairedHeights - Unify BlockTags + notification sender into ChainNotifier shared struct - Replace log-only cold_lag check with proper storage reconciliation (unwind to min of hot/cold tips on startup) - Fix PairedHeights 0/0 fallback to use genesis heights with let-else - Remove TODO about reader snapshots and redundant map_err - Replace fully-qualified HotDbRead/HistoryRead syntax with method calls Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…C config Fix EVM spec_id for RPC calls: all EVM execution paths (eth_call, eth_estimateGas, eth_createAccessList, debug tracing, bundle simulation) now derive the correct SpecId from chain config + block header instead of defaulting to PRAGUE. Move serve.rs from signet-node to signet-rpc: transport infrastructure (HTTP/WS/IPC) is now reth-free, using tokio::spawn and Handle::current() instead of reth's TaskExecutor. This removes axum, tower-http, interprocess, and ajj dependencies from signet-node. Load StorageRpcConfig from host RpcServerArgs: rpc_gas_cap, max_tracing_requests, and gas price oracle settings now flow through from reth's CLI args instead of always using defaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
[Claude Code] Closing this PR — the |
Summary
signet-rpc-storagecrate providing Ethereum JSON-RPC endpoints backed bysignet-storage(hot + cold), independent of reth'sFullNodeComponentsStorageRpcCtxwrapsUnifiedStorage,BlockTags, system constants, optionalTxCache, and RPC gas capBlockTagsprovides atomic latest/safe/finalized block tracking with sync/async resolutionblockNumber,chainIdgetBlockByHash/Number,getBlockTransactionCount*,getBlockReceipts,getBlockHeader*getTransactionByHash,getRawTransactionByHash,*ByBlockAndIndex,getTransactionReceiptgetBalance,getStorageAt,getTransactionCount,getCodecall,estimateGasviasignet-evm/trevmsendRawTransactionviaTxCachegetLogswith bloom filter matchingsignet-storage0.3.0 from crates.ioTest plan
cargo clippy -p signet-rpc-storage --all-features --all-targets— cleancargo clippy -p signet-rpc-storage --no-default-features --all-targets— cleancargo +nightly fmt— cleancargo t -p signet-rpc-storage— 33 tests passcargo doc -p signet-rpc-storage— docs build successfully🤖 Generated with Claude Code